#include "loader.h"

SceLoader::SceLoader() : sceFile(), scene(0), currentLineNumber(1), currentLine()
{
    cameraInfos[0] = 0.0;
    cameraInfos[1] = 0.0;
    cameraInfos[2] = 0.0;

    cameraInfos[3] = 0.0;
    cameraInfos[4] = 0.0;
    cameraInfos[5] = 1.0;

    cameraInfos[6] = 80;
    cameraInfos[7] = 60;
}

SceLoader::~SceLoader()
{

}

SceLoader::SceLoader(const SceLoader &sceLoader) :
    sceFile(sceLoader.sceFile), scene(sceLoader.scene), currentLineNumber(1), currentLine()
{
    cameraInfos[0] = 0.0;
    cameraInfos[1] = 0.0;
    cameraInfos[2] = 0.0;

    cameraInfos[3] = 0.0;
    cameraInfos[4] = 0.0;
    cameraInfos[5] = 1.0;

    cameraInfos[6] = 80;
    cameraInfos[7] = 60;

}

SceLoader& SceLoader::operator=(const SceLoader &sceLoader)
{
    sceFile           = sceLoader.sceFile;
    scene             = sceLoader.scene;
    currentLineNumber = 1;
    cameraInfos[0] = 0.0;
    cameraInfos[1] = 0.0;
    cameraInfos[2] = 0.0;

    cameraInfos[3] = 0.0;
    cameraInfos[4] = 0.0;
    cameraInfos[5] = 1.0;

    cameraInfos[6] = 80;
    cameraInfos[7] = 60;
    return (*this);
}


SceLoader::SceLoader(const std::string &_sceFile, Scene *_scene) :
    sceFile(_sceFile), scene(_scene), currentLineNumber(1), currentLine()
{
    cameraInfos[0] = 0.0;
    cameraInfos[1] = 0.0;
    cameraInfos[2] = 0.0;

    cameraInfos[3] = 0.0;
    cameraInfos[4] = 0.0;
    cameraInfos[5] = 1.0;

    cameraInfos[6] = 80;
    cameraInfos[7] = 60;
    exec();
}

void SceLoader::exec()
{

    GFL_ERROR error;
    error = gflLibraryInit();
    if( error )
        throw Exception(gflGetErrorString(error),EXCEPTION_INFOS);

    std::ifstream in(sceFile.data(),std::ios::binary);
    std::string tmp;
    if( !in )
        throw Exception("Can not open the specific .sce file!",EXCEPTION_INFOS);

    scene->cleanAllScene();

    while( !in.eof() )
    {
        getline(in,tmp);
        currentLine.str(tmp);
        //std::cout<<currentLine.str()<<std::endl;
        compileLine();
        currentLineNumber++;
    }
    in.close();
    gflLibraryExit();
}

inline void SceLoader::getPoint(double &x,double &y,double &z)
{
    currentLine>>x;
    currentLine>>y;
    currentLine>>z;
}

inline void SceLoader::getColor(double &x,double &y,double &z)
{
    currentLine>>x;
    currentLine>>y;
    currentLine>>z;
}

void SceLoader::identifyMainLexem()
{
    std::string tmp;
    currentLine>>tmp;
    //std::cout<<"LEXEM:"<<tmp<<std::endl;
    if( tmp == "CAMERA" )
        currentLexem = camera;
    else if( tmp == "" )
        currentLexem = eol;
    else if( tmp == "SPHERE" )
        currentLexem = sphere;
    else if( tmp == "LIGHT" )
        currentLexem = light;
    else if( tmp == "PLAN" )
        currentLexem = plan;
    else if( tmp == "TORE" )
        currentLexem = tore;
    else if( tmp == "TRIANGLE" )
        currentLexem = triangle;
    else if( tmp == "DAMIER" )
        currentLexem = damier;
    else if( tmp == "TEXTURE" )
        currentLexem = texture;
    else if( tmp == "#" )
        currentLexem = commentary;
    else if( tmp == "AMBIANT_LIGHT" )
        currentLexem = ambiantLight;
    else if( tmp == "FOG" )
        currentLexem = fog;
    else
        currentLexem = unknow;

}

void SceLoader::compileLine()
{
    //std::cout<< "[loader "<<currentLineNumber<<" ] : "<<currentLine.str()<<std::endl;

    identifyMainLexem();
    if( currentLexem == unknow)
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Unknow Lexem : " <<currentLine.str()<<std::endl;
    else if( currentLexem == sphere )
        loadSphere();
    else if( currentLexem == camera )
        loadCamera();
    else if( currentLexem == plan )
        loadPlan();
    else if( currentLexem == light )
        loadLight();
    else if( currentLexem == tore )
        loadTore();
    else if( currentLexem == triangle )
        loadTriangle();
    else if( currentLexem == damier )
        loadDamier();
    else if( currentLexem == texture )
        loadTexture();
    else if( currentLexem == ambiantLight )
        loadAmbiantLight();
    else if( currentLexem == fog )
        loadFOG();

}

void SceLoader::loadCamera()
{
    std::string tmp;
    double x,y,z,dx,dy,dz,ax,ay;
    currentLine>>tmp;
    if( tmp != "<" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Camera failed : " <<currentLine.str()<<std::endl;
    else {
    getPoint(x, y, z);
    getColor(dx,dy,dz);
    currentLine>>ax;
    currentLine>>ay;
    currentLine>>tmp;
    if( tmp != ">" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Camera failed : " <<currentLine.str()<<std::endl;
    else {

    cameraInfos[0] = x;
    cameraInfos[1] = y;
    cameraInfos[2] = z;

    cameraInfos[3] = dx;
    cameraInfos[4] = dy;
    cameraInfos[5] = dz;

    cameraInfos[6] = ax;
    cameraInfos[7] = ay;
    }}
}

void SceLoader::loadLight()
{
    std::string tmp;
    double x,y,z,r,g,b;

    currentLine>>tmp;
    if( tmp != "<" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading light failed : " <<currentLine.str()<<std::endl;
    else {
    getPoint(x,y,z);
    currentLine>>tmp;
    if( tmp != "COLOR" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading light failed : " <<currentLine.str()<<std::endl;
    else {
    getColor(r,g,b);
    currentLine>>tmp;
    if( tmp != ">" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading light failed : " <<currentLine.str()<<std::endl;
    else {
        //std::cout<<"ajout dune lumiere"<<std::endl;
        Light * light = new Light(Point3D(x,y,z), Color(r,g,b));
        scene->addLight(light);
    }}}

}


void SceLoader::loadPlan()
{
    std::string tmp;
    double x,y,z,vx,vy,vz,r,g,b;
    double dif,speC,speP,reflec,refrac,refN;
    bool material(false);

    currentLine>>tmp;
    if( tmp != "<" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Plan failed : " <<currentLine.str()<<std::endl;
    else {
    getPoint(x, y, z);
    getPoint(vx,vy,vz);
    currentLine>>tmp;
    if( tmp != "COLOR" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Plan failed : " <<currentLine.str()<<std::endl;
    else {
    getColor(r,g,b);
    currentLine>>tmp;
    if( tmp == "MATERIAL" )
    {
        material = true;
        currentLine>>dif;
        currentLine>>speC;
        currentLine>>speP;
        currentLine>>reflec;
        currentLine>>refrac;
        currentLine>>refN;
        currentLine>>tmp;
    }
    if( tmp != ">" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Plan failed : " <<currentLine.str()<<std::endl;
    else {
        Plan * plan = new Plan(Point3D(x,y,z), Vector3D(vx,vy,vz) , Color(r,g,b));
        if( material )
            plan->setMaterialComponents(dif,speC,speP,reflec,refrac,refN);
        scene->addObject(plan);
    }}}
}

void SceLoader::loadSphere()
{
    std::string tmp;
    double x,y,z,r,g,b,s;
    double dif,speC,speP,reflec,refrac,refN;
    bool material(false);

    currentLine>>tmp;
    if( tmp != "<" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading sphere failed : " <<currentLine.str()<<std::endl;
    else {
    getPoint(x,y,z);
    currentLine>>s;
    currentLine>>tmp;
    if( tmp != "COLOR" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading sphere failed : " <<currentLine.str()<<std::endl;
    else {
    getColor(r,g,b);
    currentLine>>tmp;
    if( tmp == "MATERIAL" )
    {
        material = true;
        currentLine>>dif;
        currentLine>>speC;
        currentLine>>speP;
        currentLine>>reflec;
        currentLine>>refrac;
        currentLine>>refN;
        currentLine>>tmp;
    }
    if( tmp != ">" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading sphere failed : " <<currentLine.str()<<std::endl;
    else {
        Sphere * sphere = new Sphere(Point3D(x,y,z), s , Color(r,g,b));
        if( material )
            sphere->setMaterialComponents(dif,speC,speP,reflec,refrac,refN);
            //std::cout<<"sphere : "<<refN<<std::endl;
        scene->addObject(sphere);
    }}}
}


void SceLoader::loadDamier()
{
    std::string tmp;
    double Ix,Iy,Iz,Jx,Jy,Jz;
    double r1,g1,b1,r2,g2,b2;
    currentLine>>tmp;
    if( tmp != "<" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Damier failed : " <<currentLine.str()<<std::endl;
    else {
    currentLine>>Ix;
    currentLine>>Iy;
    currentLine>>Iz;
    currentLine>>Jx;
    currentLine>>Jy;
    currentLine>>Jz;

    currentLine>>tmp;
    if( tmp != "COLOR" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Damier failed : " <<currentLine.str()<<std::endl;
    else {
    getColor(r1,g1,b1);

    currentLine>>tmp;
    if( tmp != "COLOR" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Damier failed : " <<currentLine.str()<<std::endl;
    else {
    getColor(r2,g2,b2);
    currentLine>>tmp;
    if( tmp != ">" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Damier failed : " <<currentLine.str()<<std::endl;
    else {
    Damier * damier = new Damier(Color(r1,g1,b1),Color(r2,g2,b2));
    scene->lastObjectLoad()->setXVec(Vector3D(Ix,Iy,Iz));
    scene->lastObjectLoad()->setYVec(Vector3D(Jx,Jy,Jz));
    scene->lastObjectLoad()->attachTexture(damier);
    }}}}
}


void SceLoader::loadTexture()
{
    std::string tmp;
    double Ix,Iy,Iz,Jx,Jy,Jz;
    currentLine>>tmp;
    if( tmp != "<" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Texture failed : " <<currentLine.str()<<std::endl;
    else {
    currentLine>>Ix;
    currentLine>>Iy;
    currentLine>>Iz;
    currentLine>>Jx;
    currentLine>>Jy;
    currentLine>>Jz;

    currentLine>>tmp;
    if( tmp != "FILE" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Texture failed : " <<currentLine.str()<<std::endl;
    else {
    currentLine>>tmp;

    FTexture * texture;
    try
    {
        texture = scene->addTexture((char*)tmp.data());
        scene->lastObjectLoad()->setXVec(Vector3D(Ix,Iy,Iz));
        scene->lastObjectLoad()->setYVec(Vector3D(Jx,Jy,Jz));
        scene->lastObjectLoad()->attachTexture(texture);
    }
    catch(const Exception &e)
    {
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading Texture failed : " <<currentLine.str()<<std::endl;
    }
    }}
}


void SceLoader::loadTore()
{
    std::string tmp;
    double x,y,z,r,g,b,r1,r2;
    double dif,speC,speP,reflec,refrac,refN;
    bool material(false);

    currentLine>>tmp;
    if( tmp != "<" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading tore failed : " <<currentLine.str()<<std::endl;
    else {
    getPoint(x,y,z);
    currentLine>>r1;
    currentLine>>r2;
    currentLine>>tmp;
    if( tmp != "COLOR" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading tore failed : " <<currentLine.str()<<std::endl;
    else {
    getColor(r,g,b);
    currentLine>>tmp;
    if( tmp == "MATERIAL" )
    {
        material = true;
        currentLine>>dif;
        currentLine>>speC;
        currentLine>>speP;
        currentLine>>reflec;
        currentLine>>refrac;
        currentLine>>refN;
        currentLine>>tmp;
    }
    if( tmp != ">" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading tore failed : " <<currentLine.str()<<std::endl;
    else {
        Tore * tore = new Tore(Point3D(x,y,z), r1,r2 , Color(r,g,b));
        if( material )
            tore->setMaterialComponents(dif,speC,speP,reflec,refrac,refN);
        scene->addObject(tore);
    }}}
}



void SceLoader::loadTriangle()
{
    std::string tmp;
    double x1,y1,z1,x2,y2,z2,x3,y3,z3,r,g,b;
    double dif,speC,speP,reflec,refrac,refN;
    bool material(false);

    currentLine>>tmp;
    if( tmp != "<" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading triangle failed : " <<currentLine.str()<<std::endl;
    else {
    getPoint(x1,y1,z1);
    getPoint(x2,y2,z2);
    getPoint(x3,y3,z3);
    currentLine>>tmp;
    if( tmp != "COLOR" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading triangle failed : " <<currentLine.str()<<std::endl;
    else {
    getColor(r,g,b);
    currentLine>>tmp;
    if( tmp == "MATERIAL" )
    {
        material = true;
        currentLine>>dif;
        currentLine>>speC;
        currentLine>>speP;
        currentLine>>reflec;
        currentLine>>refrac;
        currentLine>>refN;
        currentLine>>tmp;
    }
    if( tmp != ">" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading triangle failed : " <<currentLine.str()<<std::endl;
    else {
        //Triangle * triangle = new Triangle(Point3D(x1,y1,z1), Point3D(x2,y2,z2), Point3D(x3,y3,z3), Color(r,g,b));
        //if( material )
        //    triangle->setMaterialComponents(dif,speC,speP,reflec,refrac,refN);
        //scene->addObject(triangle);
    }}}
}


void SceLoader::loadAmbiantLight()
{
    std::string tmp;
    double r,g,b;

    currentLine>>tmp;
    if( tmp != "<" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading AmbiantLight failed : " <<currentLine.str()<<std::endl;
    else {
    currentLine>>tmp;
    if( tmp != "COLOR" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading AmbiantLight failed : " <<currentLine.str()<<std::endl;
    else {
    getColor(r,g,b);
    currentLine>>tmp;
    if( tmp != ">" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading AmbiantLight failed : " <<currentLine.str()<<std::endl;
    else {
        scene->setAmbiantLight(Color(r,g,b));
    }}}
}

void SceLoader::loadFOG()
{
    std::string tmp;
    double r,g,b, dist;

    currentLine>>tmp;
    if( tmp != "<" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading FOG failed : " <<currentLine.str()<<std::endl;
    else {
    currentLine>>dist;
    currentLine>>tmp;
    if( tmp != "COLOR" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading FOG failed : " <<currentLine.str()<<std::endl;
    else {
    getColor(r,g,b);
    currentLine>>tmp;
    if( tmp != ">" )
        std::cout<<"[WARNING] [line "<<currentLineNumber<<"] Loading FOG failed : " <<currentLine.str()<<std::endl;
    else {
        scene->setFogParameters(dist,Color(r,g,b));
        //std::cout<<r<<" "<<g<<" "<<b<<std::endl;
    }}}

}

